#pragma once


#include <cmath>

#include "qarchive.h"
using namespace micro::files;



namespace micro
{
namespace utils
{


class QPoint;
class QSize;
class QRect;

/*
 *  QSize this class is a wrapper of SIZE Struct
 *
 **/

class QSize : public SIZE
{
public:
    //------------------------------------------------

    QSize( SIZE sz )
    {
        cx = sz.cx;
        cy = sz.cy;
    }
    QSize( long x = 0, long y = 0 )
    {
        cx = x;
        cy = y;
    }
    void Set( long x, long y )
    {
        cx = x;
        cy = y;
    }
    operator SIZE( )
    {
        return *this;
    }
    operator LPSIZE( )
    {
        return this;
    }

    //------------------------------------------------
    inline BOOL operator==( SIZE size )
    {
        return ( size.cx == cx && size.cy == cy );
    }
    inline BOOL operator!=( SIZE size )
    {
        return ( size.cx != cx && size.cy != cy );
    }
    inline void operator+=( SIZE size )
    {
        cx += size.cx;
        cy += size.cy;
    }
    inline void operator-=( SIZE size )
    {
        cx -= size.cx;
        cy -= size.cy;
    }

    //------------------------------------------------
    inline QSize operator+( SIZE size )
    {
        return QSize ( cx + size.cx, cy + size.cy );
    }


    inline QSize operator-( SIZE size )
    {
        return QSize ( cx - size.cx, cy - size.cy );
    }

    inline QSize operator-()
    {
        return QSize( -cx, -cy );
    }

    //------------------------------------------------
    inline QPoint operator+( QPoint point ) ;
    inline QPoint operator-( QPoint point ) ;

};



class QPoint : public POINT
{
public:

    //-------------------------------------------------
    QPoint()
    {
        x = 0;
        y = 0;
    }
    QPoint ( long  lx , long ly )
    {
        x = lx;
        y = ly;
    }
    QPoint( QPoint & pt )
    {
        x = pt.x;
        y = pt.y;
    }
    QPoint( POINT & pt )
    {
        x = pt.x;
        y = pt.y;
    }
    void SetPoint( int xx, int yy )
    {
        x = xx;
        y = yy;
    }
    QPoint::QPoint( DWORD lParam )
    {
        x =  LOWORD( lParam );
        y =  HIWORD( lParam );
    }
    operator LPPOINT()
    {
        return this;
    }
    //-------------------------------------------------
    inline BOOL operator==( POINT point )
    {
        return ( point.x == x && point.y == y );
    }
    inline BOOL operator!=( POINT point )
    {
        return ( point.x != x && point.y != y );
    }
    inline void operator+=( SIZE size )
    {
        x += size.cx;
        y += size.cy;
    }
    inline void operator-=( SIZE size )
    {
        x -= size.cx;
        y -= size.cy;
    }
    inline void operator+=( POINT point )
    {
        x += point.x;
        y += point.y;
    }
    inline void operator-=( POINT point )
    {
        x -= point.x;
        y -= point.y;
    }

    //-------------------------------------------------
    inline QPoint operator+( SIZE size )
    {
        return QPoint( size.cx + x, size.cy + y );
    }
    inline QPoint operator-( SIZE size )
    {
        return QPoint( size.cx - x, size.cy - y );
    }
    inline QPoint operator-()
    {
        return QPoint( -x, -y );
    }
    inline QPoint operator+( QPoint point )
    {
        return QPoint( point.x + x, point.y + y );
    }

    //-------------------------------------------------
    inline QSize operator-( QPoint & point )
    {
        return QSize( x - point.x, y - point.y );
    }

    double Distance( QPoint & point )
    {
        return sqrt( ( x - point.x ) * ( x - point.x ) + ( y - point.y ) * ( y - point.y ) );
    }

};

/*
 *  QRect class
 *
 **/

class QRect : public RECT
{
public:


    QRect ( QPoint pt1, QPoint pt2 )
    {
        SetRect( pt1.x, pt1.y, pt2.x, pt2.y );
    }

    QRect ( int Left = 0, int Top = 0, int Right = 0, int Bottom = 0 )
    {
        left   = Left;
        top    = Top;
        right  = Right;
        bottom = Bottom;
    }

    QRect( int x, int y, QSize size )
    {
        right = ( left = x ) + size.cx;
        bottom = ( top = y ) + size.cy;
    }

    QRect( QPoint point, QSize size )
    {
        right = ( left = point.x ) + size.cx;
        bottom = ( top = point.y ) + size.cy;
    }

    //QRect(QPoint topLeft, POINT bottomRight)
    //{ left = topLeft.x; top = topLeft.y;right = bottomRight.x; bottom = bottomRight.y; }

    QRect::QRect( const RECT & srcRect )
    {
        ::CopyRect( this, &srcRect );
    }

    inline int  Width()
    {
        return ( int )right - left;
    }
    inline int Height()
    {
        return ( int )bottom - top;
    }

    inline QSize   GetSize()
    {
        return QSize( right - left, bottom - top );
    }
    inline QPoint  TopLeft()
    {
        return QPoint( left, top );
    }
    inline QPoint  BottomRight()
    {
        return QPoint( right, bottom );
    }

    inline QPoint  CenterPoint()
    {
        return QPoint( ( left + right ) / 2, ( top + bottom ) / 2 );
    }
    inline operator LPRECT()
    {
        return this;
    }
    inline operator LPCRECT()
    {
        return this;
    }
    inline BOOL  IsRectEmpty()
    {
        return ::IsRectEmpty( this );
    }
    inline BOOL  IsRectNull()
    {
        return ( left == 0 && right == 0 && top == 0 && bottom == 0 );
    }
    inline BOOL  PtInRect( POINT point )
    {
        return ::PtInRect( this, point );
    }
    inline void  SetRect( int x1, int y1, int x2, int y2 )
    {
        ::SetRect( this, x1, y1, x2, y2 );
    }
    inline void  SetRect( POINT topLeft, POINT bottomRight )
    {
        ::SetRect( this, topLeft.x, topLeft.y, bottomRight.x, bottomRight.y );
    }
    inline void  SetRectEmpty()
    {
        ::SetRectEmpty( this );
    }
    inline void  CopyRect( LPCRECT lpSrcRect )
    {
        ::CopyRect( this, lpSrcRect );
    }
    inline BOOL  EqualRect( LPCRECT lpRect )
    {
        return ::EqualRect( this, lpRect );
    }
    inline void  InflateRect( int x, int y )
    {
        ::InflateRect( this, x, y );
    }
    inline void  InflateRect( SIZE size )
    {
        ::InflateRect( this, size.cx, size.cy );
    }
    inline void  DeflateRect( int x, int y )
    {
        ::InflateRect( this, -x, -y );
    }
    inline void  DeflateRect( SIZE size )
    {
        ::InflateRect( this, -size.cx, -size.cy );
    }
    inline void  OffsetRect( int x, int y )
    {
        ::OffsetRect( this, x, y );
    }
    inline void  OffsetRect( QPoint point )
    {
        ::OffsetRect( this, point.x, point.y );
    }
    inline void  OffsetRect( SIZE size )
    {
        ::OffsetRect( this, size.cx, size.cy );
    }
    inline bool  IntersectRect( QRect * pRect1, QRect * pRect2 )
    {
        return 0 !=::IntersectRect( this, pRect1, pRect2 );
    }
    inline BOOL  UnionRect( QRect * pRect1, QRect * pRect2 )
    {
        return ::UnionRect( this, pRect1, pRect2 );
    }
    inline void  operator=( RECT & srcRect )
    {
        ::CopyRect( this, &srcRect );
    }
    inline BOOL  operator==( RECT & rect )
    {
        return ::EqualRect( this, &rect );
    }
    inline BOOL  operator!=( RECT & rect )
    {
        return !::EqualRect( this, &rect );
    }
    inline void  operator+=( QPoint point )
    {
        ::OffsetRect( this, point.x, point.y );
    }
    inline void  operator+=( SIZE size )
    {
        ::OffsetRect( this, size.cx, size.cy );
    }
    inline void  operator+=( LPCRECT lpRect )
    {
        InflateRect( lpRect );
    }
    inline void  operator-=( QPoint point )
    {
        ::OffsetRect( this, -point.x, -point.y );
    }
    inline void  operator-=( SIZE size )
    {
        ::OffsetRect( this, -size.cx, -size.cy );
    }
    inline void  operator-=( LPCRECT lpRect )
    {
        DeflateRect( lpRect );
    }
    inline void  operator&=( RECT & rect )
    {
        ::IntersectRect( this, this, &rect );
    }
    inline void  operator|=( RECT & rect )
    {
        ::UnionRect( this, this, &rect );
    }
    inline QRect operator+( QPoint pt )
    {
        QRect rect( *this );
        ::OffsetRect( &rect, pt.x, pt.y );
        return rect;
    }
    inline QRect operator-( QPoint pt )
    {
        QRect rect( *this );
        ::OffsetRect( &rect, -pt.x, -pt.y );
        return rect;
    }
    inline QRect operator+( SIZE size )
    {
        QRect rect( *this );
        ::OffsetRect( &rect, size.cx, size.cy );
        return rect;
    }
    inline QRect operator-( SIZE size )
    {
        QRect rect( *this );
        ::OffsetRect( &rect, -size.cx, -size.cy );
        return rect;
    }
    inline QRect operator&( const RECT & rc )
    {
        QRect rect;
        ::IntersectRect( &rect, this, &rc );
        return rect;
    }
    inline QRect operator|( const RECT & rc )
    {
        QRect rect;
        ::UnionRect( &rect, this, &rc );
        return rect;
    }
    inline BOOL  SubtractRect( LPCRECT lpRectSrc1, LPCRECT lpRectSrc2 )
    {
        return ::SubtractRect( this, lpRectSrc1, lpRectSrc2 );
    }

    inline void  InflateRect( LPCRECT lpRect )
    {
        left -= lpRect->left;
        top -= lpRect->top;
        right += lpRect->right;
        bottom += lpRect->bottom;
    }

    inline void  InflateRect( int l, int t, int r, int b )
    {
        left -= l;
        top -= t;
        right += r;
        bottom += b;
    }

    inline void  DeflateRect( LPCRECT lpRect )
    {
        left += lpRect->left;
        top += lpRect->top;
        right -= lpRect->right;
        bottom -= lpRect->bottom;
    }

    inline void  DeflateRect( int l, int t, int r, int b )
    {
        left += l;
        top += t;
        right -= r;
        bottom -= b;
    }

    inline QRect  MulDiv( int nMultiplier, int nDivisor )
    {
        return QRect(
                   ::MulDiv( left, nMultiplier, nDivisor ),
                   ::MulDiv( top, nMultiplier, nDivisor ),
                   ::MulDiv( right, nMultiplier, nDivisor ),
                   ::MulDiv( bottom, nMultiplier, nDivisor ) );
    }

    friend QArchive & operator<<( QArchive & ar,  const QRect & pidl );
    friend QArchive & operator>>( QArchive & ar,  const QRect & pidl );




};



QPoint QSize::operator+( QPoint point )
{
    QPoint p( point.x + cx, point.y + cy );
    return p;
}
QPoint QSize::operator-( QPoint point )
{
    return QPoint( point.x - cx, point.y - cy );
}

//
//
//
// QArchive& operator<<( QArchive& ar,  const QRect& rc )
// {
//
//     return ar;
// }
// QArchive& operator>>( QArchive& ar,  const QRect& rc )
// {
//
//     return ar;
// }



}
}//micro